package com.bluesky.example.myaop;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
import java.util.logging.Logger;

import com.bluesky.example.myaop.business.BusinessInterface;
import com.bluesky.example.myaop.business.BusinessObject;
import com.bluesky.example.myaop.interceptors.LogInterceptor;
import com.bluesky.example.myaop.interceptors.ParameterInterceptor;
import com.bluesky.example.myaop.interceptors.PerformanceInterceptor;

/**
 * this class demonstrates how to implements your own powerful AOP solution.
 * Maybe we can throw the Spring away, because mostly I use Spring because I
 * need AOP on transaction management.
 * 
 * @author jack
 * 
 */
public class ChainHandler implements InvocationHandler {
	private Logger logger = Logger.getLogger(this.getClass().getName());

	private List<MethodInterceptor> interceptors = new ArrayList<MethodInterceptor>();
	private Object delegate;

	public ChainHandler(Object delegate) {
		this.delegate = delegate;
	}

	public void addInterceptor(MethodInterceptor interceptor) {
		interceptors.add(interceptor);
	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {

		Object o = null;

		try {
			logger.info("method starts..." + method + " in "
					+ proxy.getClass().getName());
			Stack<MethodInterceptor> stack = new Stack<MethodInterceptor>();

			for (MethodInterceptor mi : interceptors) {
				mi.Before(delegate, method, args);
				stack.push(mi);
			}

			o = method.invoke(delegate, args);

			while (!stack.isEmpty()) {
				MethodInterceptor mi = stack.pop();

				mi.After(delegate, method, args);
			}

			logger.info("method ends..." + method + " in "
					+ proxy.getClass().getName());
		} catch (Exception e) {
			logger.info("Exception happends...");
			e.printStackTrace();
			// excetpion handling.
		}
		return o;
	}

	public static void main(String[] args) {
		BusinessInterface businessImp = new BusinessObject();
		ChainHandler handler = new ChainHandler(businessImp);
		BusinessInterface proxy = (BusinessInterface) Proxy.newProxyInstance(
				businessImp.getClass().getClassLoader(), businessImp.getClass()
						.getInterfaces(), handler);

		// add interceptors
		handler.addInterceptor(new LogInterceptor());
		handler.addInterceptor(new PerformanceInterceptor());
		handler.addInterceptor(new ParameterInterceptor());

		proxy.processBusiness(2, true, "xfsafsgdsfdc");
	}
}
